package com.paic.common.util;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.core.JsonPointer;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;

/**
 * Json to XServerHttpResponse, the class support {@code mapper} method to
 * generate Object Json.
 *
 * @author postonzhang
 */
public class JsonManager {

    private static final Logger log = LoggerFactory.getLogger(JsonManager.class);

    public static final String JSON_FILTER_EXCEPT_FIELD = "except-field-filter";

    /**
     * Serialized specified bean to json
     *
     * @param target specified bean
     * @return json data
     * @throws JsonProcessingException
     */
    public static String json(Object target) throws JsonProcessingException {
        // when XServer use jsonExceptField to get json, must add the
        // @JsonFilter annotation to the JavaBean, According to this when we
        // want to serialize all field in the JavaBean will cause a
        // JsonMappingException: Can not resolve BeanPropertyFilter with id
        // 'exception-field-filter'. Then put the
        // DEFAULT_JACKSON_MAPPER.writeValueAsString and jsonExceptField(target,
        // new String[]{}) in try-catch block will solve the problem
        try {
            return JsonEngine.DEFAULT_JACKSON_MAPPER.writeValueAsString(target);
        } catch (JsonMappingException e) {
            return jsonExceptField(target, new String[]{});
        }
    }

    /**
     * Serialized specified bean to json
     *
     * @param target specified bean
     * @return json data
     * @throws JsonProcessingException
     */
    public static String jsonFilter(Object target)
            throws JsonProcessingException {
        // when XServer use jsonExceptField to get json, must add the
        // @JsonFilter annotation to the JavaBean, According to this when we
        // want to serialize all field in the JavaBean will cause a
        // JsonMappingException: Can not resolve BeanPropertyFilter with id
        // 'exception-field-filter'. Then put the
        // DEFAULT_JACKSON_MAPPER.writeValueAsString and jsonExceptField(target,
        // new String[]{}) in try-catch block will solve the problem
        try {
            return JsonEngine.FILTER_JACKSON_MAPPER.writeValueAsString(target);
        } catch (JsonMappingException e) {
            return jsonExceptField(target, new String[]{});
        }
    }

    /**
     * Serialized bean to json, but exclude some fields of specified bean target
     *
     * @param target specified bean
     * @param fields exclude field name
     * @return json data
     * @throws JsonProcessingException
     */
    public static String jsonExceptField(Object target, String[] fields) throws JsonProcessingException {
        FilterProvider fp = new SimpleFilterProvider().addFilter(JSON_FILTER_EXCEPT_FIELD,
                SimpleBeanPropertyFilter.serializeAllExcept(fields));
        JsonEngine.FILTER_JACKSON_MAPPER.setFilters(fp);
        return JsonEngine.FILTER_JACKSON_MAPPER.writeValueAsString(target);
    }

    public static <T> T getBean(String json, Class<T> clazz) {
        T t = null;
        try {
            t = JsonEngine.DEFAULT_JACKSON_MAPPER.readValue(json, clazz);
        } catch (Exception e) {
            log.error("Serialized json to '" + clazz.getName() + "' occur error.", e);
        }
        return t;
    }

    public static <T> T getCompositeObject(String json, TypeReference<T> typeReference) {
        T t = null;
        try {
            t = JsonEngine.DEFAULT_JACKSON_MAPPER.readValue(json, typeReference);
        } catch (Exception e) {
            log.error("Serialized json to '" + typeReference + "' occur error.", e);
        }
        return t;
    }

    public static Map<String, Object> json2Map(String json) {
        Map<String, Object> map = new HashMap<>();
        try {
            map = JsonEngine.DEFAULT_JACKSON_MAPPER.readValue(json, new TypeReference<Map<String, Object>>() {
            });
        } catch (IOException e) {
            log.error("json parse error = {}, {}", json, e);
        }
        return map;
    }

    /**
     * @param json
     * @param attr /a/b
     * @return
     * @throws Exception
     */
    public static String getAttributeStringValue(String json, String attr) throws Exception {
        JsonNode jsonNode = JsonEngine.DEFAULT_JACKSON_MAPPER.readTree(json);
        JsonNode dataNode = jsonNode.at(JsonPointer.compile(attr));
        return dataNode.toString();
    }

    /**
     * @param json
     * @param attr /a/b
     * @return
     * @throws Exception
     */
    public static JsonNode getAttributeNode(String json, String attr) throws Exception {
        JsonNode jsonNode = JsonEngine.DEFAULT_JACKSON_MAPPER.readTree(json);
        JsonNode dataNode = jsonNode.at(JsonPointer.compile(attr));
        return dataNode;
    }

    // public static void main(String[] args) {
    // String elements =
    // HttpUtil.sendGet("http://testboss.op.my7v.com/ads/centre/dataCentre/listAllElement",
    // "");
    //
    // Map<String, Object> result =json2Map(elements);
    //
    //
    //
    // System.out.println(str);
    // }
    //
    // private class Test

}
